#include <boost/json.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>

#include <QDebug>

#include <cmath>

#include "RayTracingParameter.h"
#include <algorithm/shared/tool/checkFilePath/CheckFilePath.h>

namespace pt = boost::property_tree;
using namespace solar;

// 先设置初始数据，这些数据会出现在初始的UI界面上

void RayTracingParameter::setParameterViaFile(QString file_path)
{
    std::string std_file_path = file_path.toStdString();
    CheckFilePath::invertUrlToFilePath(std_file_path);
    file_path = QString::fromStdString(std_file_path);

    std::ifstream ifs(file_path.toStdString(), std::ios_base::in);
    pt::ptree tree;
    pt::read_json(ifs, tree);

    pt::ptree simu_tree = tree.get_child("simulation");

    num_sunshape_groups_ = simu_tree.get<int>("num_sunshape_groups");
    emit numSunshapeGroupsChanged();
    num_sunshape_lights_per_group_ = simu_tree.get<int>("num_sunshape_lights_per_group");
    emit numSunshapeLightsPerGroupChanged();
    inverse_transform_sampling_groups_ = simu_tree.get<int>("inverse_transform_sampling_groups");
    emit inverseTransformSamplingGroupsChanged();

    pixel_length_ = simu_tree.get<double>("receiver_pixel_length");
    emit pixelLengthChanged();
    microheliostat_length_ = simu_tree.get<double>("heliostat_pixel_length");
    emit microheliostatLengthChanged();

    ground_length_ = simu_tree.get<double>("ground.x");
    emit groundLengthChanged();
    ground_width_ = simu_tree.get<double>("ground.y");
    emit groundWidthChanged();

    grid_size_.set_x(simu_tree.get<double>("grid.size.x"));
    emit gridSizeXChanged();
    grid_size_.set_y(simu_tree.get<double>("grid.size.y"));
    emit gridSizeYChanged();
    grid_size_.set_z(simu_tree.get<double>("grid.size.z"));
    emit gridSizeZChanged();

    grid_pos_.set_x(simu_tree.get<double>("grid.pos.x"));
    emit gridPosXChanged();
    grid_pos_.set_y(simu_tree.get<double>("grid.pos.y"));
    emit gridPosYChanged();
    grid_pos_.set_z(simu_tree.get<double>("grid.pos.z"));
    emit gridPosZChanged();

    grid_interval_.set_x(simu_tree.get<double>("grid.interval.x"));
    emit gridIntervalXChanged();
    grid_interval_.set_y(simu_tree.get<double>("grid.interval.y"));
    emit gridIntervalYChanged();
    grid_interval_.set_z(simu_tree.get<double>("grid.interval.z"));
    emit gridIntervalZChanged();
}

// QString solar::RayTracingParameter::readRayCnt()
// {
//     return QString::number(ray_cnt_);
// }
// void solar::RayTracingParameter::writeRayCnt(const QString& str)
// {
//     // 注意这里要判断是否类中存的数据与ui传回来的数据是否相等
//     // 只有当数据真正改变时才发出信号，否则会有无线递归的风险
//     int data = str.toInt();
//     if(data != ray_cnt_)
//     {
//         ray_cnt_ = data;
//         emit rayCntChanged();
//     }
//     qDebug() <<"********** changed ray_cnt_ to: " << ray_cnt_;
// }
auto RayTracingParameter::getPixelLength() const -> float { return pixel_length_; }
auto RayTracingParameter::getMicroheliostatLength() const -> float
{
    return microheliostat_length_;
}

auto RayTracingParameter::getNumSunshapeGroups() const -> int { return num_sunshape_groups_; }
auto RayTracingParameter::getNumSunshapeLightsPerGroup() const -> int
{
    return num_sunshape_lights_per_group_;
}
auto RayTracingParameter::getInverseTransformSamplingGroups() const -> int
{
    return inverse_transform_sampling_groups_;
}

auto RayTracingParameter::getGroundLength() const -> float { return ground_length_; }
auto RayTracingParameter::getGroundWidth() const -> float { return ground_width_; }

auto RayTracingParameter::getGridSizeX() const -> float { return grid_size_.x(); }
auto RayTracingParameter::getGridSizeY() const -> float { return grid_size_.y(); }
auto RayTracingParameter::getGridSizeZ() const -> float { return grid_size_.z(); }

auto RayTracingParameter::getGridPosX() const -> float { return grid_pos_.x(); }
auto RayTracingParameter::getGridPosY() const -> float { return grid_pos_.y(); }
auto RayTracingParameter::getGridPosZ() const -> float { return grid_pos_.z(); }

auto RayTracingParameter::getGridIntervalX() const -> float { return grid_interval_.x(); }
auto RayTracingParameter::getGridIntervalY() const -> float { return grid_interval_.y(); }
auto RayTracingParameter::getGridIntervalZ() const -> float { return grid_interval_.z(); }

void RayTracingParameter::setPixelLength(const float pixel_length)
{
    if (std::abs(pixel_length_ - pixel_length) > 1e-5)
    {
        pixel_length_ = pixel_length;
        emit pixelLengthChanged();
        qDebug() << "********** changed pixel_length_ to: " << pixel_length_;
    }
}
void RayTracingParameter::setMicroheliostatLength(const float microheliostat_length)
{
    if (std::abs(microheliostat_length_ - microheliostat_length) > 1e-5)
    {
        microheliostat_length_ = microheliostat_length;
        emit microheliostatLengthChanged();
        qDebug() << "********** changed microheliostat Length to: " << microheliostat_length_;
    }
}

void RayTracingParameter::setNumSunshapeGroups(const int num_sunshape_groups)
{
    if (num_sunshape_groups_ != num_sunshape_groups)
    {
        num_sunshape_groups_ = num_sunshape_groups;
        emit numSunshapeGroupsChanged();
        qDebug() << "********** changed num sunshape groups to: " << num_sunshape_groups_;
    }
}
void RayTracingParameter::setNumSunshapeLightsPerGroup(const int num_sunshape_lights_per_group)
{
    if (num_sunshape_lights_per_group_ != num_sunshape_lights_per_group)
    {
        num_sunshape_lights_per_group_ = num_sunshape_lights_per_group;
        emit numSunshapeLightsPerGroupChanged();
        qDebug() << "********** changed num sunshape lights per group to: "
                 << num_sunshape_lights_per_group_;
    }
}
void RayTracingParameter::setInverseTransformSamplingGroups(
    const int inverse_transform_sampling_groups)
{
    if (inverse_transform_sampling_groups_ != inverse_transform_sampling_groups)
    {
        inverse_transform_sampling_groups_ = inverse_transform_sampling_groups;
        emit inverseTransformSamplingGroupsChanged();
        qDebug() << "********** changed inverse_transform_sampling_groups to: "
                 << inverse_transform_sampling_groups_;
    }
}

void RayTracingParameter::setGroundLength(const float ground_length)
{
    if (std::abs(ground_length_ - ground_length) > 1e-5)
    {
        ground_length_ = ground_length;
        emit groundLengthChanged();
        qDebug() << "********** changed ground length to: " << ground_length_;
    }
}
void RayTracingParameter::setGroundWidth(const float ground_width)
{
    if (std::abs(ground_width_ - ground_width) > 1e-5)
    {
        ground_width_ = ground_width;
        emit groundWidthChanged();
        qDebug() << "********** changed ground width to: " << ground_width_;
    }
}

void RayTracingParameter::setGridSizeX(const float grid_size_x)
{
    if (std::abs(grid_size_.x() - grid_size_x) > 1e-5)
    {
        grid_size_.set_x(grid_size_x);
        emit gridSizeXChanged();
        qDebug() << "********** changed grid_size_x to: " << grid_size_.x();
    }
}
void RayTracingParameter::setGridSizeY(const float grid_size_y)
{
    if (std::abs(grid_size_.y() - grid_size_y) > 1e-5)
    {
        grid_size_.set_y(grid_size_y);
        emit gridSizeYChanged();
        qDebug() << "********** changed grid_size_y to: " << grid_size_.y();
    }
}
void RayTracingParameter::setGridSizeZ(const float grid_size_z)
{
    if (std::abs(grid_size_.z() - grid_size_z) > 1e-5)
    {
        grid_size_.set_z(grid_size_z);
        emit gridSizeZChanged();
        qDebug() << "********** changed grid_size_z to: " << grid_size_.z();
    }
}

void RayTracingParameter::setGridPosX(const float grid_pos_x)
{
    if (std::abs(grid_pos_.x() - grid_pos_x) > 1e-5)
    {
        grid_pos_.set_x(grid_pos_x);
        emit gridPosXChanged();
        qDebug() << "********** changed grid_pos_x to: " << grid_pos_.x();
    }
}
void RayTracingParameter::setGridPosY(const float grid_pos_y)
{
    if (std::abs(grid_pos_.y() - grid_pos_y) > 1e-5)
    {
        grid_pos_.set_y(grid_pos_y);
        emit gridPosYChanged();
        qDebug() << "********** changed grid_pos_y to: " << grid_pos_.y();
    }
}
void RayTracingParameter::setGridPosZ(const float grid_pos_z)
{
    if (std::abs(grid_pos_.z() - grid_pos_z) > 1e-5)
    {
        grid_pos_.set_z(grid_pos_z);
        emit gridPosZChanged();
        qDebug() << "********** changed grid_pos_z to: " << grid_pos_.z();
    }
}

void RayTracingParameter::setGridIntervalX(const float grid_interval_x)
{
    if (std::abs(grid_interval_.x() - grid_interval_x) > 1e-5)
    {
        grid_interval_.set_x(grid_interval_x);
        emit gridIntervalXChanged();
        qDebug() << "********** changed grid_interval_x to: " << grid_interval_.x();
    }
}
void RayTracingParameter::setGridIntervalY(const float grid_interval_y)
{
    if (std::abs(grid_interval_.y() - grid_interval_y) > 1e-5)
    {
        grid_interval_.set_y(grid_interval_y);
        emit gridIntervalYChanged();
        qDebug() << "********** changed grid_interval_y to: " << grid_interval_.y();
    }
}
void RayTracingParameter::setGridIntervalZ(const float grid_interval_z)
{
    if (std::abs(grid_interval_.z() - grid_interval_z) > 1e-5)
    {
        grid_interval_.set_z(grid_interval_z);
        emit gridIntervalZChanged();
        qDebug() << "********** changed grid_interval_z to: " << grid_interval_.z();
    }
}
